#ifndef __IM_INTERNALS_H__
#define __IM_INTERNALS_H__

#include "config.h"
#include <im_base_types.h>

/**
 * @defgroup IMInternals
 * @ingroup PrivateIMBus
 * @{
 */

IM_BEGIN_DECLS

/** @def _im_return_if_fail(condition)
 * Used to validate parameters of public functions.
 * When check fail, tt logs an information and abort by default.
 * if env IMBUS_FATAL_WARNINGS is set to 0, then just returns.
 */
/** @def _im_return_val_if_fail(condition,retval)
 * Used to validate parameters of public functions.
 * When check fail, tt logs an information and abort by default.
 * if env IMBUS_FATAL_WARNINGS is set to 0, then just returns with
 * a given value.
 */


/**
 * @brief Prints a warning message to stderr.
 *
 * Can optionally be made to exit
 * fatally by setting IM_FATAL_WARNINGS, but this is rarely
 * used. This function should be considered pretty much equivalent to
 * fprintf(stderr). _im_warn_check_failed() on the other hand is
 * suitable for use when a programming mistake has been made.
 *
 * @param format printf-style format string.
 */
void    _im_warn                (const char *format,
                                 ...) IM_GNUC_PRINTF(1, 2);


/**
 * Prints a "critical" warning to stderr when an assertion fails;
 * differs from _im_warn primarily in that it prefixes the pid and
 * defaults to fatal. This should be used only when a programming
 * error has been detected. Calling this means "there is a bug"
 */
void    _im_warn_check_failed   (const char *format,
                                 ...) IM_GNUC_PRINTF(1, 2);

#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
#define __IM_FUNCTION_NAME __func__
#elif defined(__GNUC__)
#define __IM_FUNCTION_NAME __FUNCTION__
#else
#define __IM_FUNCTION_NAME "unknown function"
#endif

#ifdef IM_ENABLE_VERBOSE_MODE
void    _im_verbose_real        (const char *format,
                                 ...) IM_GNUC_PRINTF (1, 2);
IMBool  _im_is_verbose_real     (void);

#  define _im_verbose _im_verbose_real
#  define _im_is_verbose _im_is_verbose_real
#else
#  ifdef HAVE_ISO_VARARGS
#    define _im_verbose(...)
#  elif defined (HAVE_GNUC_VARARGS)
#    define _im_verbose(format...)
#  else
#    error "This compiler does not support varargs macros and thus verbose mode can't be disabled meaningfully"
#  endif
#  define _im_is_verbose() FALSE
#endif /* !IM_ENABLE_VERBOSE_MODE */

#ifdef IM_DISABLE_ASSERT
#define _im_assert(condition)
#else
void    _im_real_assert         (IMBool       condition,
                                 const char  *condition_text,
                                 const char  *file,
                                 int          line,
                                 const char  *func);
#define _im_assert(condition)                               \
    _im_real_assert ((condition) != 0, #condition, __FILE__, __LINE__, __IM_FUNCTION_NAME)
#endif /* !IM_DISABLE_ASSERT */

#ifdef IM_DISABLE_ASSERT
#define _im_assert_not_reached(explanation)
#else
void    _im_real_assert_not_reached(const char *explanation,
                                    const char *file,
                                    int         line) IM_GNUC_NORETURN;
#define _im_assert_not_reached(explanation)  \
    _im_real_assert_not_reached (explanation, __FILE__, __LINE__)
#endif /* !IM_DISABLE_ASSERT */

#ifdef IM_DISABLE_CHECKS
#define _im_return_if_fail(condition)
#define _im_return_val_if_fail(condition, val)
#else
extern const char _im_return_if_fail_warning_format[];

#define _im_return_if_fail(condition) do {                                          \
  if (!(condition)) {                                                               \
    _im_warn_check_failed (_im_return_if_fail_warning_format,                       \
                             __IM_FUNCTION_NAME, #condition, __FILE__, __LINE__);   \
    return;                                                                         \
  } } while (0)

#define _im_return_val_if_fail(condition, val) do {                                 \
  if (!(condition)) {                                                               \
    _im_warn_check_failed (_im_return_if_fail_warning_format,                       \
                             __IM_FUNCTION_NAME, #condition, __FILE__, __LINE__);   \
    return (val);                                                                   \
  } } while (0)

#endif /* !IM_DISABLE_ASSERT */

#if IM_ENABLE_DEBUG
/**
 * @brief Print debug information of slice system.
 */
void        _im_slice_print_debug_info ();

/**
 * @brief Check whether the slice allocation system
 *        is corrupt or not.
 *
 * It's mainly for debug purpose.
 */
IMBool      _im_slice_is_corrupt ();
#endif

IM_END_DECLS

#endif
/*
vi:ts=4:nowrap:ai:expandtab
*/
